|
 |
 |
| 1 // ex_counter.nxc 2 // Simulation of a digital counter odometer-like display. The 3 // counter digits are displayed in seven-segment form such as 4 // used in many electronic instrument displays. 5 6 // Right button increments count. 7 // Left button decrements count. 8 // Center button zeros count. 9 // Gray button halts and exits program. 10 11 // Buttons must be bumped (pressed and released) for operations to 12 // execute. 13 14 // DIGITS determines how many digits the counter maintains and 15 // displays. It should no bigger than 5. If not set at compile 16 // time, it will default to 3. 17 #ifndef DIGITS 18 #define DIGITS 3 19 #endif 20 21 // Counter globals 22 mutex counter_mutex; 23 bool counter_changed; 24 int counter[DIGITS]; 25 26 // Section defining 7-segment display functions 27 28 // Dimensions of the segments of a 7-segment digit 29 #define HRZ_W 8 30 #define HRZ_H 2 31 #define VRT_W 2 32 #define VRT_H 8 33 34 // Dimensions of the spaces occupied by the segments. 35 #define HRZ_CELL_W (HRZ_W + 1) 36 #define HRZ_CELL_H (HRZ_H + 1) 37 #define VRT_CELL_W (VRT_W + 1) 38 #define VRT_CELL_H (VRT_H + 1) 39 40 // Constants used to position digits on the display. 41 #define DIGIT_WIDTH (HRZ_CELL_W + 2 * VRT_CELL_W + 2) 42 #define COUNTER_WIDTH (DIGIT_WIDTH * DIGITS) 43 #define X_OFFSET ((100 - COUNTER_WIDTH) / 2) 44 #define DIGIT_HEIGHT (3 * HRZ_CELL_H + 2 * VRT_CELL_H) 45 #define Y_OFFSET ((64 - DIGIT_HEIGHT) / 2) 46 47 // Draw a horizontal segment at screen location (x, y), which is at 48 // the lower-left corner of the segment. 49 inline void hrz_segment_out(int x, int y) 50 { 51 RectOut(x, y, HRZ_W, HRZ_H, DRAW_OPT_FILL_SHAPE); 52 } 53 54 // Draw a vertical segment at screen location (x, y), which is at 55 // the lower-left corner of the segment. 56 inline void vrt_segment_out(int x, int y) 57 { 58 RectOut(x, y, VRT_W, VRT_H, DRAW_OPT_FILL_SHAPE); 59 } 60 61 /* 62 aaa 63 e b 64 e b 65 e b 66 ggg the segments of a 7-segment display 67 f c 68 f c 69 f c 70 ddd 71 72 The reference point (ref_x, ref_y) for positioning a 7-segment 73 digit on the NXT screen is at its lower right corner. 74 */ 75 76 // Draw segment aaa at its proper offset from the reference point 77 // (ref_x, ref_y). 78 inline void seg_a_out(int ref_x, int ref_y) 79 { 80 const int dx = VRT_CELL_W; 81 const int dy = 2 * HRZ_CELL_H + 2 * VRT_CELL_H; 82 hrz_segment_out(ref_x + dx, ref_y + dy); 83 } 84 85 // Draw segment bbb at its proper offset from the reference point 86 // (ref_x, ref_y). 87 inline void seg_b_out(int ref_x, int ref_y) 88 { 89 const int dx = VRT_CELL_W + HRZ_CELL_W; 90 const int dy = 2 * HRZ_CELL_H + VRT_CELL_H; 91 vrt_segment_out(ref_x + dx, ref_y + dy); 92 } 93 94 // Draw segment ccc at its proper offset from the reference point 95 // (ref_x, ref_y). 96 inline void seg_c_out(int ref_x, int ref_y) 97 { 98 const int dx = VRT_CELL_W + HRZ_CELL_W; 99 const int dy = HRZ_CELL_H; 100 vrt_segment_out(ref_x + dx, ref_y + dy); 101 } 102 103 // Draw segment ddd at its proper offset from the reference point 104 // (ref_x, ref_y). 105 inline void seg_d_out(int ref_x, int ref_y) 106 { 107 const int dx = VRT_CELL_W; 108 const int dy = 0; 109 hrz_segment_out(ref_x + dx, ref_y + dy); 110 } 111 112 // Draw segment eee at its proper offset from the reference point 113 // (ref_x, ref_y). 114 inline void seg_e_out(int ref_x, int ref_y) 115 { 116 const int dx = 0; 117 const int dy = 2 * HRZ_CELL_H + VRT_CELL_H; 118 vrt_segment_out(ref_x + dx, ref_y + dy); 119 } 120 121 // Draw segment fff at its proper offset from the reference point 122 // (ref_x, ref_y). 123 inline void seg_f_out(int ref_x, int ref_y) 124 { 125 const int dx = 0; 126 const int dy = HRZ_CELL_H; 127 vrt_segment_out(ref_x + dx, ref_y + dy); 128 } 129 130 // Draw segment ggg at its proper offset from the reference point 131 // (ref_x, ref_y). 132 inline void seg_g_out(int ref_x, int ref_y) 133 { 134 const int dx = VRT_CELL_W; 135 const int dy = HRZ_CELL_H + VRT_CELL_H; 136 hrz_segment_out(ref_x + dx, ref_y + dy); 137 } 138 139 // 7-segment numbers on the display are built up from various 140 // combinations of horizontal and vertical segments. 141 142 // Draw zero at reference point (x, Y_OFFSET). 143 void digit_0(int x) 144 { 145 seg_a_out(x, Y_OFFSET); 146 seg_b_out(x, Y_OFFSET); 147 seg_c_out(x, Y_OFFSET); 148 seg_d_out(x, Y_OFFSET); 149 seg_e_out(x, Y_OFFSET); 150 seg_f_out(x, Y_OFFSET); 151 } 152 153 // Draw one at reference point (x, Y_OFFSET). 154 void digit_1(int x) 155 { 156 seg_b_out(x, Y_OFFSET); 157 seg_c_out(x, Y_OFFSET); 158 } 159 160 // Draw twp at reference point (x, Y_OFFSET). 161 void digit_2(int x) 162 { 163 seg_a_out(x, Y_OFFSET); 164 seg_b_out(x, Y_OFFSET); 165 seg_d_out(x, Y_OFFSET); 166 seg_f_out(x, Y_OFFSET); 167 seg_g_out(x, Y_OFFSET); 168 } 169 170 // Draw three at reference point (x, Y_OFFSET). 171 void digit_3(int x) 172 { 173 seg_a_out(x, Y_OFFSET); 174 seg_b_out(x, Y_OFFSET); 175 seg_c_out(x, Y_OFFSET); 176 seg_d_out(x, Y_OFFSET); 177 seg_g_out(x, Y_OFFSET); 178 } 179 180 // Draw four at reference point (x, Y_OFFSET). 181 void digit_4(int x) 182 { 183 seg_b_out(x, Y_OFFSET); 184 seg_c_out(x, Y_OFFSET); 185 seg_e_out(x, Y_OFFSET); 186 seg_g_out(x, Y_OFFSET); 187 } 188 189 // Draw five at reference point (x, Y_OFFSET). 190 void digit_5(int x) 191 { 192 seg_a_out(x, Y_OFFSET); 193 seg_c_out(x, Y_OFFSET); 194 seg_d_out(x, Y_OFFSET); 195 seg_e_out(x, Y_OFFSET); 196 seg_g_out(x, Y_OFFSET); 197 } 198 199 // Draw six at reference point (x, Y_OFFSET). 200 void digit_6(int x) 201 { 202 seg_a_out(x, Y_OFFSET); 203 seg_c_out(x, Y_OFFSET); 204 seg_d_out(x, Y_OFFSET); 205 seg_e_out(x, Y_OFFSET); 206 seg_f_out(x, Y_OFFSET); 207 seg_g_out(x, Y_OFFSET); 208 } 209 210 // Draw seven at reference point (x, Y_OFFSET). 211 void digit_7(int x) 212 { 213 seg_a_out(x, Y_OFFSET); 214 seg_b_out(x, Y_OFFSET); 215 seg_c_out(x, Y_OFFSET); 216 seg_e_out(x, Y_OFFSET); 217 } 218 219 // Draw eight at reference point (x, Y_OFFSET). 220 void digit_8(int x) 221 { 222 seg_a_out(x, Y_OFFSET); 223 seg_b_out(x, Y_OFFSET); 224 seg_c_out(x, Y_OFFSET); 225 seg_d_out(x, Y_OFFSET); 226 seg_e_out(x, Y_OFFSET); 227 seg_f_out(x, Y_OFFSET); 228 seg_g_out(x, Y_OFFSET); 229 } 230 231 // Draw nine at reference point (x, Y_OFFSET). 232 void digit_9(int x) 233 { 234 seg_a_out(x, Y_OFFSET); 235 seg_b_out(x, Y_OFFSET); 236 seg_c_out(x, Y_OFFSET); 237 seg_d_out(x, Y_OFFSET); 238 seg_e_out(x, Y_OFFSET); 239 seg_g_out(x, Y_OFFSET); 240 } 241 242 // Given the digit place of digit, return its horizontal offset on 243 // the NXT screen. The place of a digit is its index in the counter 244 // array. 245 int offset(int place) 246 { 247 return X_OFFSET + (DIGITS - place - 1) * DIGIT_WIDTH; 248 } 249 250 // Section defining counter control tasks 251 252 // Given a button's ID number, return true if that button has been 253 // bumped. Otherwise return false. 254 bool button_bumped(const byte btn) 255 { 256 bool result = false; 257 if (ButtonPressed(btn, false)) 258 { 259 while (ButtonPressed(btn, true)); 260 PlayFile("! Click.rso"); 261 result = true; 262 } 263 return result; 264 } 265 266 // When the right button is bumped, increment the counter. The 267 // for-loop performs carry propagation. 268 task increment() 269 { 270 byte carry; 271 while(true) 272 { 273 Acquire(counter_mutex); 274 if ((! counter_changed) && button_bumped(BTNRIGHT)) 275 { 276 carry = 1; 277 for (int i = 0; (carry == 1) && (i < DIGITS); ++i) 278 { 279 int d = counter[i] + carry; 280 if (d > 9) 281 { 282 d = 0; 283 carry = 1; 284 } 285 else carry = 0; 286 counter[i] = d; 287 } 288 counter_changed = true; 289 } 290 Release(counter_mutex); 291 Yield(); 292 } 293 } 294 295 // When the left button is bumped, decrement the counter. The 296 // for-loop performs borrow propagation. 297 task decrement() 298 { 299 byte borrow; 300 while(true) 301 { 302 Acquire(counter_mutex); 303 if ((! counter_changed) && button_bumped(BTNLEFT)) 304 { 305 borrow = 1; 306 for (int i = 0; (borrow == 1) && (i < DIGITS); ++i) 307 { 308 int d = counter[i] - borrow; 309 if (d < 0) 310 { 311 d = 9; 312 borrow = 1; 313 } 314 else borrow = 0; 315 counter[i] = d; 316 } 317 counter_changed = true; 318 } 319 Release(counter_mutex); 320 Yield(); 321 } 322 } 323 324 // When the center button is bumped, zero the counter. 325 task zero() 326 { 327 while(true) 328 { 329 Acquire(counter_mutex); 330 if ((! counter_changed) && button_bumped(BTNCENTER)) 331 { 332 ArrayInit(counter, 0, DIGITS); 333 counter_changed = true; 334 } 335 Release(counter_mutex); 336 Yield(); 337 } 338 } 339 340 // When the count has changed, update the NXT screen with the new 341 // count. 342 task show_count() 343 { 344 while(true) 345 { 346 Acquire(counter_mutex); 347 if (counter_changed) 348 { 349 ClearScreen(); 350 for (int i = 0; i < DIGITS; ++i) 351 { 352 switch (counter[i]) 353 { 354 case 0: 355 digit_0(offset(i)); 356 break; 357 case 1: 358 digit_1(offset(i)); 359 break; 360 case 2: 361 digit_2(offset(i)); 362 break; 363 case 3: 364 digit_3(offset(i)); 365 break; 366 case 4: 367 digit_4(offset(i)); 368 break; 369 case 5: 370 digit_5(offset(i)); 371 break; 372 case 6: 373 digit_6(offset(i)); 374 break; 375 case 7: 376 digit_7(offset(i)); 377 break; 378 case 8: 379 digit_8(offset(i)); 380 break; 381 case 9: 382 digit_9(offset(i)); 383 break; 384 } 385 } 386 counter_changed = false; 387 } 388 Release(counter_mutex); 389 Yield(); 390 } 391 } 392 393 // Section defining start-up code. 394 395 task main() 396 { 397 Precedes(show_count, zero, increment, decrement); 398 counter = 0; 399 counter_changed = true; 400 }
|
 |
 |
|
 |